#ifndef DATA_HPP  
#define DATA_HPP 
#include<pthread.h>
#include"util.hpp"
#include"myconfig.hpp"
#include<unordered_map>

namespace cloud{


typedef struct BackupInfo{      //一个文件的属性
    bool pack_flag;             //是否被压缩
    size_t fsize;               //文件大小
    time_t mtime;               //最后一次修改时间
    time_t atime;               //最后一次访问时间
    std::string real_path;       //文件的真实路径
    std::string pack_path;       //该文件被压缩后的路径
    std::string url;             //下载该文件的路径
    bool NewBackupInfo(const std::string &realpath)   //使用之前写的工具类util.hpp->文件大小，文件最后修改，访问时间
    {    FileUtil fu(realpath);                       //以及服务端配置文件myconfig.hpp->文件的压缩路径，文件压缩的后缀名，文件的下载路径
            if(fu.Exists()==false)
            {
                
                std::cout<<"new backupinfo file not exists!"<<std::endl;
                return false;}


        Config *config=Config::GetInstance();            //获取单例句柄
        std::string packdir=config->GetPackDir();        //获取服务器的压缩路径
        std::string packsuffix=config->GetpackFileSuffix();//获取文件压缩的后缀名
        std::string download_prefix=config->GetDownloadPrefix();//下载路径
   
    this->pack_flag=false;                                 //是否被压缩
    this->fsize=fu.FileSize();                             //文件的大小
    this->mtime=fu.LastMTime();                            //文件的最后修改时间
    this->atime=fu.LastATime();                            //文件最后访问时间
    this->real_path=realpath;                              //文件的真实路径

    this->pack_path=packdir+fu.FileName()+packsuffix;       //文件如果被压缩，应该放的路径 ./packdir/bundle.h.lz
    this->url=download_prefix+fu.FileName();                //文件下载时的url /download/bundle.h
    return true;

    }

}BackupInfo;   ///该结构体的作用是保存一个备份文件的属性



class DataManger                             
{
private:
std::string _backup_file;               //持久化存储所有备份文件的属性的文件路径名
pthread_rwlock_t _rwlock;               //因为查看一个文件信息可以是读，写，当有线程要读来查看文件属性时，此时也允许别人来写，使用读写锁，写互斥
std::unordered_map<std::string,BackupInfo> _table;//文件的url和自己的文件属性对应存在map中
public:
DataManger()
{
 _backup_file=Config::GetInstance()->GetBackupFile();
 pthread_rwlock_init(&_rwlock,nullptr);//初始化读写锁
 InitLoad();                           //将持久化文件属性用来初始化


}

~DataManger()
{

pthread_rwlock_destroy(&_rwlock);    //读写锁的销毁
}


bool Insert(const BackupInfo &info)  //上传一个文件后就要插入一个文件的属性到 _table
{
pthread_rwlock_wrlock(&_rwlock);          //此时要写的话，加读写锁
_table[info.url]=info;                    //       /download/bundle.h   ----------BackupInfo[0]

pthread_rwlock_unlock(&_rwlock);
Storage();                                //保存到持久化文件中去

}
bool Update(const BackupInfo &info)
{pthread_rwlock_wrlock(&_rwlock);
_table[info.url]=info;                    //修改后覆盖式写入



pthread_rwlock_unlock(&_rwlock);
Storage();
}


bool GetOneByURL(const std::string &url,BackupInfo*info)     //根据文件的url在table中找到自己的文件属性_table[i].sceond
{
  pthread_rwlock_wrlock(&_rwlock);                          //读属性，加锁
  auto it=_table.find(url);                                 //根据url找对应文件属性
  if(it==_table.end())
  { pthread_rwlock_unlock(&_rwlock);                        //没找到
    return false;
  }
  *info=it->second;                                         //找到了，输出型参数带出去
  pthread_rwlock_unlock(&_rwlock);
  return true;
}
bool GetOneByRealPath(const std::string &realpath,BackupInfo*info)    //根据文件的实际路径找到对应的文件属性
{
    pthread_rwlock_wrlock(&_rwlock);                            //读属性，加锁 
    auto it=_table.begin();
    for(;it!=_table.end();++it){                                //遍历table
     if(it->second.real_path==realpath)                         //如果查找的实际路径在table中找到
     {
      *info=it->second;                                         //输出型参数带出去
      pthread_rwlock_unlock(&_rwlock);
      return true;


     }



    }
    pthread_rwlock_unlock(&_rwlock);
    return false;

}
bool GetAll(std::vector<BackupInfo>*arry)        //将table中所有的文件属性信息保存在arry中
{
  pthread_rwlock_wrlock(&_rwlock);
  auto it=_table.begin();
  for(;it!=_table.end();++it)
     {
        arry->push_back(it->second);             //遍历table,文件属性插入



     }
     pthread_rwlock_unlock(&_rwlock);
     return true;



}

 bool Storage()                                    //将table中的文件属性保存在_backup_file
 {
     std::vector<BackupInfo>array;                 //将table中的文件属性读到array
     this->GetAll(&array);
     Json::Value root;                            //vector<BackupInfo>          
     for(int i=0;i<array.size();i++)
        {
         Json::Value item;                             //单个文件属性 BackupInfo
         item["pack_flag"]=array[i].pack_flag;
         item["fsize"]=(Json::Int64)array[i].fsize;
         item["atime"]=(Json::Int64)array[i].atime;
         item["mtime"]=(Json::Int64)array[i].mtime;
         item["real_path"]=array[i].real_path;
         item["pack_path"]=array[i].pack_path;
         item["url"]=array[i].url;
         root.append(item);

        }

        std::string body;
        JsonUtil::Serialize(root,&body);                 //序列化到字符串body中去

        FileUtil fu(_backup_file);               
        fu.SetContent(body);                              //将序列化的body写入_backup_file，持久化存储里面
        return true; 

 }
   
   bool InitLoad()                                       //读取_backup_file，写入table
   {
    FileUtil fu(_backup_file);
    if(fu.Exists()==false)
    {return true;}
    std::string body;
    fu.GetContent(&body);                               //将_backup_file内容读到body
    Json::Value root;                                   
    JsonUtil::UnSerialize(body,&root);                 //反序列化
    for(int i=0;i<root.size();i++)
       {
        BackupInfo info ;
        info.pack_flag=root[i]["pack_flag"].asBool();
        info.fsize=root[i]["fsize"].asInt64();
        info.atime=root[i]["atime"].asInt64();
        info.mtime=root[i]["mtime"].asInt64();
        info.pack_path=root[i]["pack_path"].asString();
        info.real_path=root[i]["real_path"].asString();
        info.url=root[i]["url"].asString();
        Insert(info);                                     //一次循环是将一个文件属性插入到table中





       }







    return true;
   }




};


}



#endif